/**
 * Project: dx.redisClient
 * 
 * File Created at 2016年4月22日
 * 
 * Copyright 2015-2015 dx.com Croporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * DongXue software Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with dx.com.
 */
package com.dx.redisClient.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.dx.pf.commons.utils.StringUtil;

import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.JedisCommands;
import redis.clients.jedis.Tuple;
import redis.clients.jedis.params.geo.GeoRadiusParam;
import redis.clients.jedis.params.sortedset.ZAddParams;
import redis.clients.jedis.params.sortedset.ZIncrByParams;

/** 
* @ClassName: RedisDaoImpl 
* @Description: Redis数据库dao接口实现
* @author wuzhenfang(wzfbj2008@163.com)
* @date 2016年4月22日 下午5:41:20 
* @version V1.0 
*/
public class RedisDaoImpl implements IRedisDao{
	
	 //默认过期时间为一天
    public static final int DEFAULT_EXPIRED_TIME = 60 * 60 * 24; // 1 day
	
    public JedisCommands client = null;
	
	@Override
	public JedisCommands getClient() {
		if(client == null){
			//TODO
		}
		return client;
	}
	
	/**
	 * 判断key值是否存在
	 * @param key：键
	 * @return 存在返回true，不存在返回false
	 */
	public boolean exists(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().exists(key);
		}else{
			return false;
		}
	}

	/**
	 * 如果删除的key不存在，则直接忽略
	 * @param key：键值
	 * @return 被删除的keys的数量
	 */
	public Long delKey(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().del(key);
		}else{
			return 0l;
		}
	}

	/**
	 * 设置key的过期时间，超过时间后，将会自动删除该key
	 * @param key：键值
	 * @param seconds时长，超过这个时长后过期
	 * @return:1 如果成功设置过期时间.0 如果key不存在或者不能设置过期时间
	 */
	public Long expire(String key, int seconds){
		if (!StringUtil.isEmpty(key)) {
			return getClient().expire(key, seconds);
		}else{
			return 0l;
		}
	}

	/**
	 * 都用于为 key 设置生存时间
	 * @param key ：键值
	 * @param unixTime UNIX 时间戳
	 * @return 1 如果设置了过期时间 0 如果没有设置过期时间，或者不能设置过期时间
	 */
	public Long expireAt(String key, long unixTime){
		if (!StringUtil.isEmpty(key)) {
			return getClient().expireAt(key, unixTime);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 以秒为单位返回 key 的剩余生存时间
	 * @param key：键值
	 * @return 如果key不存在返回-2,如果key存在但是已经过期返回-1
	 */
	public Long ttl(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().ttl(key);
		}else{
			return 0l;
		}
	}

	// ======================================================
	// ========================String========================
	// ======================================================
	
	/**
	 * 获取key对应的String值
	 * @param key：键值
	 * @return 返回一个String值
	 */
	public String get(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().get(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 设置key的新值，返回key的旧值
	 * @param key键值
	 * @param value新值
	 * @return key不存在返回为空
	 */
	public String getSet(final String key, final String value){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)) {
			return getClient().getSet(key, value);
		}else{
			return null;
		}
	}
	
	/**
	 * 返回key对应的字符串value的子串，这个子串是由start和end位移决定的（两者都在string内）
	 * 左下标是从0开始，-1就是最后一个字符，-2就是倒数第二个
	 * @param key
	 * @param start
	 * @param end
	 * @return
	 */
	public String getSubStr(String key, int start, int end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().getrange(key, start, end);
		}else{
			return null;
		}
	}
	/**
	 * key的string类型value的长度
	 * @param key
	 * @return key对应的字符串value的长度，或者0(key不存在)
	 */
	public Long getStrLenth(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().strlen(key);
		}else{
			return 0l;
		}
	}
	/**
	 * 给指定key值的字符串值追加value
	 * @param key：键值
	 * @param value：值
	 * @return 返回字符串长度
	 */
	public Long append(String key, String value){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)) {
			return getClient().append(key, value);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 设置key值对应的值为String类型的Value
	 * @param key:键值
	 * @param value:值
	 * @return 设置成功返回OK
	 */
	public String set(String key, String value) {
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)) {
			return getClient().set(key, value);
		} else {
			return null;
		}
	}
	
	/**
	 * 设置key值对应的值为对象类型的Value
	 * @param key:键值
	 * @param value:Object实体值，只存标记RedisType实体和RedisKey的字段
	 * @return 设置成功返回OK
	 */
	public String set(String key, Object value) {
		if (!StringUtil.isEmpty(key) && value != null) {
			//TODO
			return null;
		} else {
			return null;
		}
	}
	
	/**
	 * 设置一个键值，只有当该值不存在时，设置成功
	 * 可以使用该功能做分布式锁
	 * @param key:键值
	 * @param value:值
	 * @return返回1:设置成功，0:设置失败
	 */
	public Long setStringValueNotExists(String key, String value) {
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)) {
			return getClient().setnx(key, value);
		} else {
			return 0l;
		}
	}

	/**
	 * 设置Key-Value值并设置过期时间（单位：秒）
	 * @param key:键值
	 * @param value:值
	 * @param seconds:过期时间
	 * @return
	 */
	public String setStringExpire(String key, String value, int seconds){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)) {
			return getClient().setex(key,seconds, value);
		}else{
			return null;
		}
	}

	/**
	 * 执行原子加1操作
	 * @param key:键值
	 * @return
	 */
	public Long incr(String key){
		if (!StringUtil.isEmpty(key)){
			return getClient().incr(key);
		}else{
			return 0l;
		}
	}

	/**
	 * 在指定的整数上原子加
	 * @param key:键值
	 * @param integer:指定整数
	 * @return
	 */
	public Long incrBy(String key, long integer){
		if (!StringUtil.isEmpty(key)){
			return getClient().incrBy(key, integer);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 在指定的浮点数上原子加
	 * @param key:键值
	 * @param value:指定浮点型可以是负
	 * @return
	 */
	public double incrByFloat(String key, float value){
		if (!StringUtil.isEmpty(key)){
			return getClient().incrByFloat(key, value);
		}else{
			return 0d;
		}
	}

	/**
	 * 整数原子减一
	 * @param key:键值
	 * @return
	 */
	public Long decr(String key){
		if (!StringUtil.isEmpty(key)){
			return getClient().decr(key);
		}else{
			return 0l;
		}
	}

	/**
	 * 在指定的整数上原子减一
	 * @param key:键值
	 * @param integer:指定整数
	 * @return
	 */
	public Long decrBy(String key, long integer){
		if (!StringUtil.isEmpty(key)){
			return getClient().decrBy(key, integer);
		}else{
			return 0l;
		}
	}

	// ======================================================
	// ========================List==========================
	// ======================================================
	// 其实就是String类型的双向链表
	//1、栈 先进后出
	//2、队列 先进先出
	//3、阻塞队列：避免轮询，当队列为空则阻塞，等有任务存在则返回。
	
	/**
	 * 返回存储在 key 里的list的长度
	 * @param key
	 * @return
	 */
	public long getListLength(String key){
		if (!StringUtil.isEmpty(key)){
			return getClient().llen(key);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 返回列表里的元素的索引 index位置存储的值
	 * @param key
	 * @param index 0 是表示第一个元素， 1 表示第二个元素，并以此类推
	 *              负数索引用于指定从列表尾部开始索引的元素。在这种方法下，
	 *              -1 表示最后一个元素，-2 表示倒数第二个元素，并以此往前推
	 * @return
	 */
	public String getForListIndex(String key,int index){
		if (!StringUtil.isEmpty(key)){
			return getClient().lindex(key, index);
		}else{
			return null;
		}
	}
	
	/**
	 * 把 value 插入存于 key 的列表中在基准值 pivot 的前面或后面。
	 * 当 key 不存在时，这个list会被看作是空list，任何操作都不会发生。
	 * 当 key 存在，但保存的不是一个list的时候，会返回error。
	 * @param key list key
	 * @param where 插在pivot值前面：BEFORE, 插在pivot值后面：AFTER
	 * @param pivot 需要对比的值
	 * @param value 插入值
	 * @return 经过插入操作后的list长度，或者当 pivot 值找不到的时候返回 -1
	 */
	public long insertListOffsetValue(String key,BinaryClient.LIST_POSITION where, String pivot,String value){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)){
			return getClient().linsert(key, where, pivot, value);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 从key 对应list 中删除count 个和value 相同的元素
	 * @param key
	 * @param value 
	 * @param count count<0 时，按从头到尾的顺序删除,
	 * 		  count>0 时，按从尾到头的顺序删除,
	 *        count = 0: 移除所有值为 value 的元素
	 * @return 被移除的元素个数
	 */
	public long delListIncludeValue(String key,String value,int count){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)){
			return getClient().lrem(key, count, value);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 返回存储在 key 的列表里指定范围内的元素。 start 和 end 偏移量都是基于0的下标，
	 * 即list的第一个元素下标是0（list的表头），第二个元素下标是1，以此类推。
	 * 偏移量也可以是负数，表示偏移量是从list尾部开始计数,-1 表示列表的最后一个元素，-2 是倒数第二个
	 * list里面的元素是从0到100，那么 LRANGE list 0 10 这个命令会返回11个元素，即最右边的那个元素也会被包含在内
	 * @param key
	 * @param start 开始位置 
	 * @param end 结束位置
	 * @return 指定范围里的列表元素
	 */
	public List<String> getSubListForList(String key,int start,int end){
		if (!StringUtil.isEmpty(key)){
			return getClient().lrange(key, start, end);
		}else{
			return null;
		}
	}
	
	/**
	 * 设置list 中指定下标的元素值
	 * @param key list的key
	 * @param index 下标位置，可以为负数尾部开始计数，-1 表示列表的最后一个元素，-2 是倒数第二个
	 * @param value 元素值
	 * @return 返回一个状态
	 */
	public String updateListForIndex(String key, long index, String value){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(value)){
			return getClient().lset(key, index, value);
		}else{
			return null;
		}
	}
	
	/**
	 * 将所有指定的值插入到存于 key 的列表的尾部。（从左尾部-->右头部）
	 * 如果 key 不存在，那么在进行 push 操作前会创建一个空列表。
	 * 如果 key 对应的值不是一个 list 的话，那么会返回一个错误.
	 * 把多个元素 push进入列表
	 * @param key
	 * @param values a b c，返回的列表是 c 为第一个元素， b 为第二个元素， a 为第三个元素
	 * @return 当 key 不存在的时候不会进行任何操作
	 */
	public long addListEnd(String key,String... values){
		if (!StringUtil.isEmpty(key) && values != null && values.length > 0){
			return getClient().lpush(key, values);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 将所有指定的值插入到存于 key 的列表的尾部。（从左尾部-->右头部）
	 * 当 key 不存在的时候不会进行任何操作.
	 * @param key
	 * @param values
	 * @return 当 key 不存在的时候不会进行任何操作
	 */
	public long addListEndExists(String key, String... values) {
		if (!StringUtil.isEmpty(key) && values != null && values.length > 0) {
			return getClient().lpushx(key, values);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 向存于 key 的列表的头部插入所有指定的值。（从左尾部-->右头部）
	 * 如果 key 不存在，那么会创建一个空的列表然后再进行 push 操作。 
	 * 当 key 保存的不是一个列表，那么会返回一个错误。
	 * @param key
	 * @param values a b c 会返回一个列表，其第一个元素是 a ，第二个元素是 b ，第三个元素是 c
	 * @return push 操作后的列表长度
	 */
	public long addListHead(String key,String... values){
		if (!StringUtil.isEmpty(key) && values != null && values.length > 0){
			return getClient().rpush(key, values);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 将所有指定的值插入到存于 key 的列表的头部。（从左尾部-->右头部）
	 * 当 key 不存在的时候不会进行任何操作.
	 * @param key
	 * @param values
	 * @return 当 key 不存在的时候不会进行任何操作
	 */
	public long addListHeadExists(String key, String... values) {
		if (!StringUtil.isEmpty(key) && values != null && values.length > 0) {
			return getClient().rpushx(key, values);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 移除并且返回 key 对应的 list 的尾部第一个元素（从左尾部-->右头部）
	 * @param key
	 * @return 元素的值
	 */
	public String popListEnd(String key) {
		if (!StringUtil.isEmpty(key)) {
			return getClient().lpop(key);
		} else {
			return null;
		}
	}
	
	/**
	 * 移除并且返回 key 对应的 list 的头部第一个元素（从左尾部-->右头部）
	 * @param key
	 * @return 元素的值
	 */
	public String popListHead(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().rpop(key);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回存储在 key 里的queue的长度
	 * @param key
	 * @return
	 */
	public long getQueueLength(String key){
		return getListLength(key);
	}
	/**
	 * 入队列
	 * @param key
	 * @param values
	 * @return 入队后的长度
	 */
	public long pushQueue(String key,String... values){
		return addListEnd(key, values);//lpush
	}
	
	/**
	 * 出队列
	 * @param key
	 * @return 出队值
	 */
	public String popQueue(String key){
		return popListHead(key);//rpop
	}
	
	/**
	 * 是一个阻塞的队列弹出
	 * @param key key值
	 * @param timeout 超时时间
	 * @return 其中第一个元素是弹出元素的 key，第二个元素是 value。
	 */
	public List<String> popBlockQueue(String key,int timeout) {
		if (!StringUtil.isEmpty(key)) {
			return getClient().brpop(timeout, key);//brpop
		} else {
			return null;
		}
	}
	
	/**
	 * 返回存储在 key 里的Stack的长度
	 * @param key
	 * @return
	 */
	public long getStackLength(String key){
		return getListLength(key);
	}
	
	/**
	 * 入堆栈操作
	 * @param key
	 * @param value
	 * @return 入堆栈后的长度
	 */
	public long pushStack(String key,String value){
		return addListEnd(key, value);//lpush
	}
	
	/**
	 * 出堆栈操作
	 * @param key
	 * @return 出堆栈
	 */
	public String popStack(String key){
		if (!StringUtil.isEmpty(key)){
			return getClient().lpop(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 是一个阻塞的堆栈弹出
	 * @param timeout 超时时间
	 * @param key key值
	 * @return 其中第一个元素是弹出元素的 key，第二个元素是 value。
	 */
	public List<String> popBlockStack(String key,int timeout){
		if (!StringUtil.isEmpty(key)){
			return getClient().blpop(timeout,key);
		}else{
			return null;
		}
	}
	
	// ======================================================
	// ========================hashes=======================
	// ======================================================
	// hash 是一个string 类型的field和value的映射
	// hash 特别适合用于存储对象
	// hash-max-zipmap-entries 64 #配置字段最多64 个
	// hash-max-zipmap-value 512 #配置value 最大为512 字节
	
	/**
	 * 测试指定hash中的field是否存在
	 * @param key 指定hash的key
	 * @param field 
	 * @return
	 */
	public boolean hashFieldExist(String key ,String field){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field)){
			return getClient().hexists(key, field);
		}else{
			return false;
		}
	}
	
	/**
	 * 设置 key 指定的哈希集中指定字段的值。
	 * 如果 key 指定的哈希集不存在，会创建一个新的哈希集并与 key 关联。
	 * 如果字段在哈希集中存在，它将被重写。
	 * @param key 键值
	 * @param field 对象中字段
	 * @param value 值
	 * @return 0如果field原来在map里面已经存在,1如果field是一个新的字段
	 */
	public long setHash(String key, String field, String value) {
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field) && !StringUtil.isEmpty(value)) {
			return getClient().hset(key, field, value);
		} else {
			return -1;
		}
	}
	
	/**
	 * 设置hash中的field指定值
	 * 如果key不存在则先创建。
	 * 如果field存在返回0设置失败，不存在返回1设置成功。
	 * @param key 键值
	 * @param field 对象中字段
	 * @param value 值 
	 * @return 如果field存在返回0设置失败，不存在返回1设置成功。
	 */
	public long setHashNotExist(String key, String field, String value){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field) && !StringUtil.isEmpty(value)) {
			return getClient().hsetnx(key, field, value);
		} else {
			return -1;
		}
	}
	
	/**
	 * 对指定hash执行原子浮点数操作
	 * @param key 指定hash的key
	 * @param field hash中的field
	 * @param value float类型的值
	 * @return 返回执行后的值
	 */
	public double incrByFloatHashField(String key, String field, float value){
		if(!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field)){
			return getClient().hincrByFloat(key, field, value);
		}else{
			return 0d;
		}
	}

	/**
	 * 增值操作执行后的该字段的值
	 * 如果 key 不存在，会创建一个新的哈希集并与 key 关联。
	 * 如果字段不存在，则字段的值在该操作执行前被设置为 0
	 * @param key
	 * @param field
	 * @param value
	 * @return 增值操作执行后的该字段的值
	 */
	public long incrByHashField(String key, String field, long value){
		if(!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field)){
			return getClient().hincrBy(key, field, value);
		}else{
			return 0;
		}
	}
	
	
//	public long setHash(String key,Object value){
//		if (!StringUtil.isEmpty(key) && value != null) {
//			getClient().
//			return getClient().hmset();
//		} else {
//			return -1;
//		}
//	}
	
	/**
	 * 获取指定hash中的field值
	 * @param key hash的键
	 * @param field 字段名
	 * @return 返回字段的值
	 */
	public String getHashFieldValue(String key, String field){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(field)) {
			return getClient().hget(key, field);
		} else {
			return null;
		}
	}
	
	/**
	 * 获取指定hash中的多个字段值
	 * @param key hash的键值
	 * @param fields 指定的字段列表
	 * @return
	 */
	public List<String> getHashFieldValues(String key, String...fields){
		if (!StringUtil.isEmpty(key) && fields != null && fields.length > 0 ) {
			return getClient().hmget(key, fields);
		} else {
			return null;
		}
	}
	
	/**
	 * 获取指定hash中的所有的字段值
	 * @param key hash键
	 * @return 返回hash的所有的键对应的值
	 */
	public Map<String,String> getHashFieldValues(String key){
		if (!StringUtil.isEmpty(key) ){
			return getClient().hgetAll(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 返回指定hash 的field 数量
	 * @param key hash键
	 * @return field数量
	 */
	public Long getHashLength(String key){
		if (!StringUtil.isEmpty(key) ){
			return getClient().hlen(key);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 返回 key 指定的哈希集中所有字段的名字
	 * @param key
	 * @return 哈希集中的字段列表，当 key 指定的哈希集不存在时返回空列表
	 */
	public Set<String> getHashAllFields(String key){
		if (!StringUtil.isEmpty(key) ){
			return getClient().hkeys(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 返回删除hash的field数量
	 * @param key
	 * @param field
	 * @return 返回从哈希集中成功移除的域的数量，不包括指出但不存在的那些域
	 */
	public Long delHashField(String key,String field){
		if (!StringUtil.isEmpty(key) ){
			return getClient().hdel(key, field);
		}else{
			return -1l;
		}
	}
	
	/**
	 * 返回删除hash的field数量
	 * @param key
	 * @param fields
	 * @return 返回从哈希集中成功移除的域的数量，不包括指出但不存在的那些域
	 */
	public Long delHashField(String key,String... fields){
		if (!StringUtil.isEmpty(key) ){
			return getClient().hdel(key, fields);
		}else{
			return -1l;
		}
	}
	
	/**
	 * 删除整个hash中的field
	 * @param key
	 * @return
	 */
	public boolean delHash(String key) {
		if (!StringUtil.isEmpty(key)) {
			Set<String> fields = this.getHashAllFields(key);
			if (fields != null) {
				return getClient().hdel(key, fields.toArray(new String[fields.size()])) > 0;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}
	
	/**
	 * 返回hash 的所有value
	 * @param key
	 * @return
	 */
	public List<String> getHashAllValue(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().hvals(key);
		} else {
			return null;
		}
	}
	
	
	// ======================================================
	// ========================Set===========================
	// ======================================================
	//set 是string 类型的无序集合
	//hash table 会随着添加或者删除自动的调整大小。需要注意的是调整hash table 
	//大小时候需要同步（获取写锁）会阻塞其他读写操作.
	//关于set 集合类型除了基本的添加删除操作，其他有用的操作还包含集合的
	//取并集(union)，交集(intersection)，差集(difference)。通过这些操作可以很容易的实现sns
	//中的好友推荐和blog 的tag 功能.
	
	/**
	 * 添加一个或多个指定的member元素到集合的 key中.
	 * 指定的一个或者多个元素member 如果已经在集合key中存在则忽略.
	 * 如果集合key 不存在，则新建集合key,并添加member元素到集合key中.
	 * @param key
	 * @param value
	 * @return 新成功添加到集合里元素的数量,不包括已经存在于集合中的元素.
	 */
	public long addSet(String key ,String... value){
		if (!StringUtil.isEmpty(key)) {
			return getClient().sadd(key, value);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回名称为key 的set 的元素个数
	 * @param key
	 * @return set数量
	 */
	public long getSetCount(String key){
		if(!StringUtil.isEmpty(key)){
			return getClient().scard(key);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 返回key集合所有的元素
	 * @param key
	 * @return
	 */
	public Set<String> getAllSet(String key){
		if(!StringUtil.isEmpty(key)){
			return getClient().smembers(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 随机返回名称为key 的set 的一个元素，但是不删除元素
	 * @param key
	 * @return 返回随机的元素，如果key不存在则返回null.
	 */
	public String getRandomSet(String key){
		if(!StringUtil.isEmpty(key)){
			return getClient().srandmember(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 随机返回名称为key 的set 的多个元素，但是不删除元素
	 * @param key
	 * @param count
	 * @return 返回一个随机的元素数组，如果key不存在则返回一个空的数组.
	 */
	public List<String> getRandomSet(String key,int count){
		if(!StringUtil.isEmpty(key)){
			return getClient().srandmember(key, count);
		}else{
			return null;
		}
	}
	
	/**
	 * 随机返回并删除名称为key 的set 中一个元素
	 * @param key
	 * @return 删除的元素
	 */
	public String popRandomSet(String key){
		if(!StringUtil.isEmpty(key)){
			return getClient().spop(key);
		}else{
			return null;
		}
	}
	
	/**
	 * 随机返回并删除名称为key 的set 中多个元素
	 * @param key
	 * @param count
	 * @return 删除的元素
	 */
	public Set<String> popRandomSet(String key,int count){
		if(!StringUtil.isEmpty(key)){
			return getClient().spop(key, count);
		}else{
			return null;
		}
	}
	
	/**
	 * 删除set中指定的成员
	 * @param key
	 * @param member
	 * @return 从集合中移除元素的个数，不包括不存在的成员
	 */
	public long delSet(String key,String...member){
		if(!StringUtil.isEmpty(key)){
			return getClient().srem(key, member);
		}else{
			return 0l;
		}
	}
	
	/**
	 * 返回成员 member 是否是存储的集合 key的成员
	 * @param key
	 * @param member
	 * @return
	 */
	public boolean containMemberSet(String key,String member){
		if(!StringUtil.isEmpty(key)){
			return getClient().sismember(key, member);
		}else{
			return false;
		}
	}
	
	// ======================================================
	// ========================Sort=Set======================
	// ======================================================
	//set 的基础上增加了一个顺序属性，这一属性在添加修改元素的时候可以指定，
	//每次指定后，zset 会自动重新按新的值调整顺序。可以理解为有两列的mysql 表，一列存value，一列存顺序。
	//操作中key理解为zset的名字,每个元素都会关联一个double类型的score.
	//
	//
	
	/**
	 * 返回有序集key中元素的个数
	 * @param key zset键值
	 * @return 元素的个数
	 */
	public long getScoreSetCount(String key){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zcard(key);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回有序集key中，score值在min和max之间(默认包括score值等于min或max)的成员个数
	 * @param key zset键值
	 * @param min
	 * @param max
	 * @return 指定分数范围的元素个数
	 */
	public long getScoreSetCount(String key, String min, String max) {
		if (!StringUtil.isEmpty(key)) {
			return getClient().zcount(key, min, max);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回有序集key中，score值在min和max之间(默认包括score值等于min或max)的成员个数
	 * @param key zset键值
	 * @param min
	 * @param max
	 * @return 指定分数范围的元素个数
	 */
	public long getScoreSetCount(String key, double min, double max) {
		if (!StringUtil.isEmpty(key)) {
			return getClient().zcount(key, min, max);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回按照成员元素排序，member值在min和max之间(默认包括score值等于min或max)的成员个数
	 * 如：当在一个有序集合所有元素以相同分数插入，则使按字典排序。
	 * @param key
	 * @param min
	 * @param max
	 * @return 指定范围的元素个数
	 */
	public long getScoreSetCountByMemberOrderBy(String key, String min, String max) {
		if (!StringUtil.isEmpty(key)) {
			return getClient().zlexcount(key, min, max);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 按照元素的的分值排序，于元素的值对比（非分值），
	 * 返回值在最小值 min 及最大值 max 之间的所有元素。
	 * 如果有序集合中的元素存在不同的分值，所返回的元素将不确定。
	 * 元素被认为是从最低到最高的分值进行排序；
	 * 字典顺序用于以相等的分数的元素；
	 * 两个开始和结束是从零开始的索引，其中0是第一个元素，1是下一个元素等等。
	 * 它们也可以是表示偏移量从有序集的结尾，以-1作为排序的集合的最后一个元素，-2倒数第二元素等负数
	 * @param key zsetkey值
	 * @param min 与元素对比的最小值（闭区间） 需要验证
	 * @param max 与原始对比的最大值（闭区间） 需要验证
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByMemberScoreSet(String key, String min , String max ){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByLex(key, min, max);
		} else {
			return null;
		}
	}
	
	/**
	 * 按照元素的的分值排序，于元素的值对比（非分值），
	 * 返回值在最小值 min 及最大值 max 之间的所有元素。
	 * 类似于 SQL 语法中的 SELECT LIMIT offset,count 语句
	 * 如果有序集合中的元素存在不同的分值，所返回的元素将不确定。
	 * 元素被认为是从最低到最高的分值进行排序；
	 * 字典顺序用于以相等的分数的元素；
	 * 两个开始和结束是从零开始的索引，其中0是第一个元素，1是下一个元素等等。
	 * 它们也可以是表示偏移量从有序集的结尾，以-1作为排序的集合的最后一个元素，-2倒数第二元素等负数
	 * @param key zsetkey值
	 * @param min 与元素对比的最小值
	 * @param max 与元素对比的最大值
	 * @param offset 偏移位置 offset
	 * 				如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count 偏移量
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByMemberScoreSet(String key, String min , String max ,int offset,int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByLex(key, min, max, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回存储在key的排序元素集合在指定位置的范围。
	 * 元素被认为是从最低到最高的分值进行排序；
	 * @param key 键值
	 * @param start 开始位置 
	 * 		    两个开始和停止是从零开始的索引，其中0是第一个元素，1是下一个元素等等
	 * @param end 结束位置
	 *       表示偏移量从有序集的尾部，以-1作为排序的集合的最后一个元素，-2倒数第二元素等负数。
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByIndexScoreSet(String key, long start, long end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrange(key, start, end);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回有序集key中，指定区间内的成员。
	 * 成员的位置按score值递减(从大到小)来排列。
	 * 具有相同score值的成员按字典序的反序排列。
	 * @param key 键值
	 * @param start 开始位置
	 * @param end 结束位置
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangOrderDesScoreInScoreSet(String key, long start, long end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrange(key, start, end);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回有序集key中，指定区间内的成员。
	 * 成员的位置按score值递减(从大到小)来排列。
	 * 具有相同score值的成员按字典序的反序排列。
	 * @param key 键值
	 * @param start 开始位置
	 * @param end  结束位置
	 * @return 返回一个符合范围的元素和分数组成的map
	 */
	public Map<String,Double> getRangMSOrderDesScoreInScoreSet(String key, long start, long end){
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrevrangeWithScores(key, start, end));
		} else {
			return null;
		}
	}
	
	/**
	 * 返回值在最小值 min 及最大值 max 之间的所有元素
	 * 成员的位置按score值递减(从大到小)来排列。
	 * 具有相同score值的成员按字典序的反序排列。
	 * @param key  键值
	 * @param max 与元素对比的最大值
	 * @param min 与元素对比的最小值
	 * @return 返回元素集合
	 */
	public Set<String> getRangOrderDesScoreIndexInScoreSet(String key, String max, String min){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByLex(key, max, min);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回值在最小值 min 及最大值 max 之间的所有元素
	 * 成员的位置按score值递减(从大到小)来排列。
	 * 具有相同score值的成员按字典序的反序排列。
	 * @param key  键值
	 * @param max 与元素对比的最大值
	 * @param min 与元素对比的最小值
	 * @param offset偏移位置 offset
	 * 				如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count 
	 * @return 返回元素集合
	 */
	public Set<String> getRangOrderDesScoreIndexInScoreSet(String key, String max, String min, int offset, int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByLex(key, max, min, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max 最大分数
	 * @param min 最小分数
	 * @return 指定分数范围的元素列表
	 */
	public Set<String> getRangOrderDesScoreByScoreInScoreSet(String key, double max, double min){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByScore(key, max, min);
		} else {
			return null;
		}
	}
	
	/**
	 * 回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max  最大分数
	 * @param min  最小分数
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return 指定分数范围的元素列表
	 */
	public Set<String> getRangOrderDesScoreByScoreInScoreSet(String key, double max, double min,int offset, int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByScore(key, max, min, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max  最大分数
	 * @param min  最小分数
	 * @return 指定分数范围的元素列表
	 */
	public Set<String> getRangOrderDesScoreByScoreInScoreSet(String key, String max, String min){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByScore(key, max, min);
		} else {
			return null;
		}
	}
	
	/**
	 * 回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max  最大分数
	 * @param min  最小分数
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count 偏移量
	 * @return 指定分数范围的元素列表
	 */
	public Set<String> getRangOrderDesScoreByScoreInScoreSet(String key, String max, String min,int offset, int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrangeByScore(key, max, min, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max 最大分数
	 * @param min 最小分数
	 * @return 指定分数范围的元素和分数列表
	 */
	public Map<String,Double> getRangMSOrderDesScoreByScoreInScoreSet(String key, String max, String min){
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrevrangeByScoreWithScores(key, max, min));
		} else {
			return null;
		}
	}
	/**
	 * 返回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max  最大分数
	 * @param min  最小分数
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return 指定分数范围的元素和分数列表
	 */
	public Map<String,Double> getRangMSOrderDesScoreByScoreInScoreSet(String key, String max, String min, int offset, int count){
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrevrangeByScoreWithScores(key, max, min, offset, count));
		} else {
			return null;
		}
	}
	/**
	 * 返回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max  最大分数
	 * @param min  最小分数
	 * @return 指定分数范围的元素和分数列表
	 */
	public Map<String,Double> getRangMSOrderDesScoreByScoreInScoreSet(String key, double max, double min){
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrevrangeByScoreWithScores(key, max, min));
		} else {
			return null;
		}
	}
	/**
	 * 返回key的有序集合中的分数在max和min之间的所有元素（包括分数等于max或者min的元素）。
	 * 与有序集合的默认排序相反，元素被认为是从高分到低具有相同分数的元素按字典反序。
	 * @param key 键值
	 * @param max 最大分数
	 * @param min 最小分数
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return 指定分数范围的元素和分数列表
	 */
	public Map<String,Double> getRangMSOrderDesScoreByScoreInScoreSet(String key, double max, double min, int offset, int count){
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrevrangeByScoreWithScores(key, max, min, offset, count));
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值
	 * @param max 最大值
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByScoreInScoreSet(String key ,double min, double max){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByScore(key, min, max);
		} else {
			return null;
		}
	}
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值 
	 * @param max 最大值
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count 偏移量
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByScoreInScoreSet(String key ,double min, double max,int offset,int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByScore(key, min, max, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值 
	 * @param max 最大值
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByScoreInScoreSet(String key, String min, String max){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByScore(key, min, max);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值 
	 * @param max 最大值
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return 返回一个符合范围的元素集
	 */
	public Set<String> getRangByScoreInScoreSet(String key, String min, String max,int offset,int count){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrangeByScore(key, min, max, offset, count);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值 
	 * @param max 最大值
	 * @return 返回一个符合范围的元素集
	 */
	public Map<String, Double> getRangMemScoreByScoreInScoreSet(String key, String min, String max) {
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrangeByScoreWithScores(key, min, max));
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值
	 * @param max 最大值
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return  返回一个符合范围的元素集
	 */
	public Map<String, Double> getRangMemScoreByScoreInScoreSet(String key, String min, String max, int offset, int count) {
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrangeByScoreWithScores(key, min, max, offset, count));
		} else {
			return null;
		}
	}
	
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值
	 * @param max 最大值
	 * @return 返回一个符合范围的元素集
	 */
	public Map<String, Double> getRangMemScoreByScoreInScoreSet(String key, double min, double max) {
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrangeByScoreWithScores(key, min, max));
		} else {
			return null;
		}
	}
	/**
	 * 返回储存在键 key 对应的有序集合（Sorted set）中且分值（Socre）
	 * 在最大值 max 及最小值 min 之间（包括值等于 min 或 max 的元素）的所有元素.
	 * 所有元素被认为是按分值从小到大排序的.
	 * @param key 键值
	 * @param min 最小值 
	 * @param max 最大值
	 * @param offset 偏移位置 offset
	 * 			如果偏移 offset 很大，在获得所需返回元素之前，需要遍历有序集合以定位偏移offset处的元素，时间复杂度总计为 O(N)
	 * @param count  偏移量
	 * @return 返回一个符合范围的元素集
	 */
	public Map<String, Double> getRangMemScoreByScoreInScoreSet(String key, double min, double max, int offset, int count) {
		if (!StringUtil.isEmpty(key)) {
			return convertSetTupleToMap(getClient().zrangeByScoreWithScores(key, min, max, offset, count));
		} else {
			return null;
		}
	}
	
	/**
	 * 将set中成员和分数转换成map
	 * @param memScore
	 * @return 返回map
	 */
	private Map<String, Double>  convertSetTupleToMap(Set<Tuple> memScore){
		Map<String, Double> retMap = new HashMap<String, Double>();
		if (memScore.size() > 0) {
			for (Tuple tuple : memScore) {
				retMap.put(tuple.getElement(), tuple.getScore());
			}
			return retMap;
		}
		return null;
	}
	
	/**
	 * 返回给定元素对应的score
	 * @param key 键值
	 * @param member 元素
	 * @return 元素对应的score
	 */
	public double getScoreInScoreSet(String key, String member){
		if (!StringUtil.isEmpty(key) && !StringUtil.isEmpty(member)) {
			return getClient().zscore(key, member);
		} else {
			return 0d;
		}
	}
	
	/**
	 * 返回名称为key 的zset 中member 元素的排名即下标
	 * 排名：按score 从小到大排序
	 * @param key 键值
	 * @param member 元素
	 * @return 元素的排名(按score 从小到大排序)即下标
	 */
	public long getIndexScoreSet(String key, String member){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrank(key, member);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回名称为key 的zset 中member 元素的排名即下标
	 * 排名：按score 从大到小排序
	 * @param key 键值
	 * @param member 元素
	 * @return 元素的排名(按score 从大到小排序)即下标
	 */
	public Long getIndexByDescScoreSet(String key, String member){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrevrank(key, member);
		} else {
			return null;
		}
	}
	
	/**
	 * 名称为key 的zset 中添加元素member，score 用于排序。
	 * 如果该元素已经存在，则根据score 更新该元素的顺序
	 * @param key zset键值
	 * @param score 分
	 * @param member 元素
	 * @return 返回整型添加到有序集合，不包括被更新元素元素的数量
	 */
	public Long addScoreSet(String key, double score, String member){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zadd(key, score, member);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 名称为key 的zset 中添加元素member，score 用于排序。
	 * 如果该元素已经存在，则根据score 更新该元素的顺序
	 * @param key zset键值
	 * @param score 分
	 * @param member 元素
	 * @param params
	 * 		  XX:只有更新已经存在的元素，不会添加元素。
	 *        NX:不更新已经存在的元素,只是添加新元素。
	 *        CH:添加新元素，也更新已经存在的元素。
	 * @return 返回整型添加到有序集合，不包括被更新元素元素的数量
	 */
	public Long addScoreSet(String key, double score, String member,ZAddParams params){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zadd(key, score, member, params);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 名称为key 的zset 中添加元素member，score 用于排序。
	 * 如果该元素已经存在，则根据score 更新该元素的顺序
	 * @param key zset键值
	 * @param scoreMembers 元素与分数的map对
	 * @return 返回整型添加到有序集合，不包括被更新元素元素的数量
	 */
	public Long addScoreSet(String key, final Map<String,Double> scoreMembers){
		if (!StringUtil.isEmpty(key) && scoreMembers != null && scoreMembers.size() >0 ) {
			return getClient().zadd(key, scoreMembers);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 名称为key 的zset 中添加元素member，score 用于排序。
	 * 如果该元素已经存在，则根据score 更新该元素的顺序
	 * @param key zset键值
	 * @param scoreMembers 元素与分数的map对
	 * @param params 
	 * 		  XX:只有更新已经存在的元素，不会添加元素。
	 *        NX:不更新已经存在的元素,只是添加新元素。
	 *        CH:添加新元素，也更新已经存在的元素。
	 * @return 返回整型添加到有序集合，不包括被更新元素元素的数量
	 */
	public Long addScoreSet(String key, final Map<String,Double> scoreMembers,ZAddParams params){
		if (!StringUtil.isEmpty(key) && scoreMembers != null && scoreMembers.size() >0 ) {
			return getClient().zadd(key, scoreMembers, params);
		} else {
			return 0l;
		}
	}
	/**
	 * 为有序集key的成员member的score值加上增量increment。
	 * 如果key中不存在member，就在key中添加一个member，score是increment（就好像它之前的score是0.0）。
	 * 如果key不存在，就创建一个只含有指定member成员的有序集合。
	 * @param key zset键值
	 * @param score 必须是字符串表示的整数值或双精度浮点数，并且能接受double精度的浮点数。
	 *              也有可能给一个负数来减少score的值
	 * @param member 元素
	 * @return member成员的新score值
	 */
	public double incrbyScoreSet(String key, double score, String member){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zincrby(key, score, member);
		} else {
			return 0d;
		}
	}
	
	/**
	 * 为有序集key的成员member的score值加上增量increment。
	 * 如果key中不存在member，就在key中添加一个member，score是increment（就好像它之前的score是0.0）。
	 * 如果key不存在，就创建一个只含有指定member成员的有序集合。
	 * @param key zset键值
	 * @param score 必须是字符串表示的整数值或双精度浮点数，并且能接受double精度的浮点数。
	 *              也有可能给一个负数来减少score的值
	 * @param member 元素
	 * @param params
	 *        xx:只有更新已经存在的元素，不会添加元素。
	 *        nx:不更新已经存在的元素,只是添加新元素。
	 *        incr:添加新元素，也更新已经存在的元素。
	 * @return member成员的新score值
	 */
	public double incrbyScoreSet(String key, double score, String member ,ZIncrByParams params){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zincrby(key, score, member, params);
		} else {
			return 0d;
		}
	}
	
	/**
	 * 删除名称为key 的zset 中的元素member
	 * @param key
	 * @param members
	 * @return
	 */
	public long delScoreSet(String key, String... members){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zrem(key, members);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 删除有序集合存储在由最小和最大指定的字典范围之间的所有键元素.
	 * 可以认为存储在键 key中的有序集合中的元素是按字典序排序的，
	 * 然后删除值在最小值 min 及最大值 max 之间的所有元素
	 * @param key
	 * @param min 最小值
	 * @param max 最大值
	 * @return 返回整数删除的元素数量
	 */
	public long delRangByOrderMemberScoreSet(String key, String min, String max){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zremrangeByLex(key, min, max);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 删除的有序集合保存在key的最小值和最大值(含)之间的分数的所有元素
	 * @param key
	 * @param start 开始
	 * @param end 结束
	 * @return 返回整数，删除的元素数量
	 */
	public long delRangByOrderScoreScoreSet(String key, String start, String end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zremrangeByScore(key, start, end);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 删除的有序集合保存在key的最小值和最大值(含)之间的分数的所有元素
	 * @param key
	 * @param start 开始分数
	 * @param end 结束分数
	 * @return 返回整数，删除的元素数量
	 */
	public long delRangByOrderScoreScoreSet(String key, double start, double end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zremrangeByScore(key, start, end);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 删除有序集合保存在key开始和结束的排序所有元素.
	 * 无论是开始和结束都以0基础索引，其中0是得分最低的元素。
	 * 这些索引可以是负数，在那里它们表明起始于具有最高得分的元素偏移。
	 * 例如：-1是具有最高得分的元素，-2与第二最高得分等的元素
	 * @param key
	 * @param start
	 * @param end
	 * @return  返回整数，删除的元素数量
	 */
	public long delRangByRankScoreSet(String key, long start, long end){
		if (!StringUtil.isEmpty(key)) {
			return getClient().zremrangeByRank(key, start, end);
		} else {
			return 0l;
		}
	}
	
	// ======================================================
	// ========================GEO===========================
	// ======================================================
	//位置信息的服务（Location Based Service，LBS）,在位置服务的挑战中，常见的是计算两个位置是否相邻的问题。
	//位置信息由一个四元组构成，（经度、纬度、海拔、时间）
	//另一个常见的地理位置操作就是找出特定范围之内的其他存在的地点
	//可以将用户给定的地理位置信息储存起来， 并对这些信息进行操作.
	/**
	 * 添加一个经纬度地理位置
	 * @param key 键值
	 * @param member 名字
	 * @param longitude 经度
	 * @param latitude 纬度
	 * @return 添加成功的数量
	 */
	public Long addLocationGEO(String key, String member, double longitude, double latitude){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geoadd(key, longitude, latitude, member);
		} else {
			return 0l;
		}
	}
	/**
	 * 一次添加过个经纬度地理信息
	 * @param key 键值
	 * @param memberCoordinateMap 名字对应的经纬度信息
	 * @return 添加成功的数量
	 */
	public Long addLocationsGEO(String key, Map<String, GeoCoordinate> memberCoordinateMap){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geoadd(key, memberCoordinateMap);
		} else {
			return 0l;
		}
	}
	
	/**
	 * 返回一个经纬度的列表
	 * @param key 键值
	 * @param members 成员元素
	 * @return 返回一个经纬度的列表，其中第一个元素为经度第二个为纬度
	 */
	public List<GeoCoordinate> getLocationsGEO(String key, String... members){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geopos(key, members);
		} else {
			return null;
		}
	}
	
	/**
	 * 返回一个经纬度的列表
	 * 该命令将返回11个字符的Geohash字符串，所以没有精度Geohash，损失相比，使用内部52位表示。
	 * 返回的geohashes具有以下特性：他们可以缩短从右边的字符。它将失去精度，但仍将指向同一地区。
	 * 它可以在 geohash.org 网站使用，网址 http://geohash.org/<geohash-string>。
	 * 查询例子：http://geohash.org/sqdtr74hyu0.
	 * 与类似的前缀字符串是附近，但相反的是不正确的，这是可能的，用不同的前缀字符串附近。
	 * @param key 键值
	 * @param members 成员元素
	 * @return 一个数组， 数组的每个项都是一个 geohash 。 命令返回的 geohash 的位置与用户给定的位置元素的位置一一对应.
	 */
	public List<String> getLocationsGEOHash(String key, String... members){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geohash(key, members);
		} else {
			return null;
		}
	}
	
	
	/**
	 * 计算两个位置之间的距离,默认使用米为单位
	 * @param key 键值
	 * @param fromLocationMember 从位置的元素名称
	 * @param toLocationMember 到位置的元素名称
	 * @return 两个位置之间的距离，默认使用米为单位。
	 */
	public Double getLongFromLocationToLocation(String key, String fromLocationMember,String toLocationMember){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geodist(key, fromLocationMember, toLocationMember);
		} else {
			return 0d;
		}
	}
	
	/**
	 * 计算两个位置之间的距离
	 * @param key 键值
	 * @param fromLocationMember 从位置的元素名称
	 * @param toLocationMember 到位置的元素名称
	 * @param unit 返回单位
	 *        m 表示单位为米。
	 *        km 表示单位为千米。
	 *        mi 表示单位为英里。
	 *        ft 表示单位为英尺。
	 * @return 两个位置之间的距离
	 */
	public Double getLongFromLocationToLocation(String key, String fromLocationMember,String toLocationMember,GeoUnit unit){
		if (!StringUtil.isEmpty(key)) {
			return getClient().geodist(key, fromLocationMember, toLocationMember,unit);
		} else {
			return 0d;
		}
	}
	
	//使用用户给定的经纬度作为计算范围时的中心点
	/**
	 * 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素
	 * @param key  键值
	 * @param longitude 经度
	 * @param latitude 纬度
	 * @param radius 范围值，半径内范围
	 * @param unit 距离的单位
	 *            m 表示单位为米。
	 *            km 表示单位为千米。
	 *            mi 表示单位为英里。
	 *            ft 表示单位为英尺。
	 * @return 返回范围为的元素及距离和经纬度列表
	 */
	public List<GeoRadiusResponse> getLocationMembersByRange(String key, double longitude, double latitude, double radius,GeoUnit unit){
		if (!StringUtil.isEmpty(key)) {
			return getClient().georadius(key, longitude, latitude, radius, unit);
		} else {
			return null;
		}
	}
	
	/**
	 * 以给定的经纬度为中心， 返回键包含的位置元素当中， 与中心的距离不超过给定最大距离的所有位置元素
	 * @param key  键值
	 * @param longitude 经度
	 * @param latitude 纬度
	 * @param radius 范围值，半径内范围
	 * @param unit 距离的单位
	 *            m 表示单位为米。
	 *            km 表示单位为千米。
	 *            mi 表示单位为英里。
	 *            ft 表示单位为英尺。
	 * @param param 额外参数
	 *        WITHDIST: 在返回位置元素的同时， 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
	 *        WITHCOORD: 将位置元素的经度和维度也一并返回。
	 *        count：获取前 N个匹配元素，不用全部元素
	 * 位置元素的排序方式：
	 *        ASC: 根据中心的位置， 按照从近到远的方式返回位置元素。
	 *        DESC: 根据中心的位置， 按照从远到近的方式返回位置元素。
	 * @return 返回范围为的元素及距离和经纬度列表
	 */
	public List<GeoRadiusResponse> getLocationMembersByRange(String key, double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param){
		if (!StringUtil.isEmpty(key)) {
			return getClient().georadius(key, longitude, latitude, radius, unit, param);
		} else {
			return null;
		}
	}
	
	//使用储存在位置集合里面的某个地点作为中心点
	/**
	 * 找出位于指定范围内的元素，指定成员的位置被用作查询的中心。
	 * @param key  键值
	 * @param member 成员
	 * @param radius 范围值，半径内范围 
	 * @param unit 距离的单位
	 *            m 表示单位为米。
	 *            km 表示单位为千米。
	 *            mi 表示单位为英里。
	 *            ft 表示单位为英尺。
	 * @return 返回范围为的元素及距离和经纬度列表
	 */
	public List<GeoRadiusResponse> getLocationMembersByCacheMember(String key, String member, double radius, GeoUnit unit){
		if (!StringUtil.isEmpty(key)) {
			return getClient().georadiusByMember(key, member, radius, unit);
		} else {
			return null;
		}
	}
	
	/**
	 * 
	 * @param key  键值
	 * @param member
	 * @param radius 范围值，半径内范围
	 * @param unit 距离的单位
	 *            m 表示单位为米。
	 *            km 表示单位为千米。
	 *            mi 表示单位为英里。
	 *            ft 表示单位为英尺。
	 * @param param 额外参数
	 *        WITHDIST: 在返回位置元素的同时， 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。
	 *        WITHCOORD: 将位置元素的经度和维度也一并返回。
	 *        count：获取前 N个匹配元素，不用全部元素
	 * 位置元素的排序方式：
	 *        ASC: 根据中心的位置， 按照从近到远的方式返回位置元素。
	 *        DESC: 根据中心的位置， 按照从远到近的方式返回位置元素。
	 * @return 返回范围为的元素及距离和经纬度列表
	 */
	public List<GeoRadiusResponse> getLocationMembersByCacheMember(String key, String member, double radius, GeoUnit unit, GeoRadiusParam param){
		if (!StringUtil.isEmpty(key)) {
			return getClient().georadiusByMember( key,  member,  radius,  unit,  param);
		} else {
			return null;
		}
	}
	
	
}
